package com.sheliduan.itlearning.common.controller;

import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.sheliduan.itlearning.common.aspect.ApiOperationLog;
import com.sheliduan.itlearning.common.aspect.AuthAccess;
import com.sheliduan.itlearning.common.enums.ErrorCodeEnum;
import com.sheliduan.itlearning.common.exception.BizException;
import com.sheliduan.itlearning.common.model.vos.UploadFileRspVO;
import com.sheliduan.itlearning.common.utils.MinioUtil;
import com.sheliduan.itlearning.common.utils.ResponseData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;

/**
 * @author: 断舍离
 * @date: 2025/2/7 7:41
 * @description: 文件上传
 **/
@RestController
@RequestMapping("/file")
@CrossOrigin //解决跨域问题
@Slf4j
public class FileController {

    private static final String ROOT_PATH = System.getProperty("user.dir") + File.separator + "files";
    private static final String CHUNK_PATH = ROOT_PATH + File.separator + "chunks";

    @Autowired
    private MinioUtil minioUtil;

    /*
     * 上传文件
     * */
    @PostMapping("/upload")
    @ApiOperationLog(description = "上传接口")
    public ResponseData upload(@RequestParam MultipartFile file) throws IOException {
        try {
            // 上传文件
            String url = minioUtil.uploadFile(file);
            // 构建成功返参，将图片的访问链接返回
            return ResponseData.success(url);
        } catch (Exception e) {
            // 手动抛出业务异常，提示 "文件上传失败"
            throw new BizException(ErrorCodeEnum.FILE_UPLOAD_FAILED);
        }
    }

    @GetMapping("/download/{fileName}")
    @ApiOperationLog(description = "下载接口")
    @AuthAccess
    public void download(@PathVariable String fileName, HttpServletResponse response) throws IOException {
        String suffixName = fileName.substring(fileName.lastIndexOf("."));
        String filePath = null;
        if(suffixName.equalsIgnoreCase(".jpeg") ||
                suffixName.equalsIgnoreCase(".jpg") ||
                suffixName.equalsIgnoreCase(".png")) {
            filePath = ROOT_PATH + File.separator + "picture" + File.separator + fileName;
        }
        if(suffixName.equalsIgnoreCase(".mp4") || suffixName.equalsIgnoreCase(".mov")) {
            filePath = ROOT_PATH + File.separator + "video" + File.separator + fileName;
        }
        System.out.println(filePath);
        if(!FileUtil.exist(filePath)){
            return;
        }
        // 根据文件路径读文件到byte数组
        byte[] bytes = FileUtil.readBytes(filePath);
        ServletOutputStream outputStream = response.getOutputStream();
        // 写入文件的字节流数组
        outputStream.write(bytes);
        outputStream.flush();
        outputStream.close();
    }

    /*
     * 上传分片文件
     */
    @PostMapping("/chunk/upload")
    @ApiOperationLog(description = "分片上传接口")
    public ResponseData uploadChunk(
            @RequestParam MultipartFile file,
            @RequestParam String fileHash,
            @RequestParam Integer chunkIndex,
            @RequestParam Integer totalChunks) throws IOException {
        
        // 创建分片存储目录
        String chunkDirPath = CHUNK_PATH + File.separator + fileHash;
        File chunkDir = new File(chunkDirPath);
        if (!chunkDir.exists()) {
            chunkDir.mkdirs();
        }

        // 保存分片文件
        String chunkFilePath = chunkDirPath + File.separator + chunkIndex;
        File chunkFile = new File(chunkFilePath);
        file.transferTo(chunkFile);

        return ResponseData.success("分片上传成功");
    }

    /*
     * 合并分片文件并上传到MinIO
     */
    @PostMapping("/chunk/merge")
    @ApiOperationLog(description = "合并分片接口")
    public ResponseData mergeChunks(
            @RequestParam String fileHash,
            @RequestParam String fileName,
            @RequestParam Integer totalChunks) throws Exception {

        String chunkDirPath = CHUNK_PATH + File.separator + fileHash;
        String tempFilePath = ROOT_PATH + File.separator + fileName;
        File tempFile = new File(tempFilePath);
        String url = null;
        FileOutputStream fos = null;
        FileInputStream fis = null;

        try {
            // 创建临时合并文件
            if (!tempFile.exists()) {
                tempFile.createNewFile();
            }

            // 合并分片
            fos = new FileOutputStream(tempFile);
            byte[] buffer = new byte[1024];
            for (int i = 0; i < totalChunks; i++) {
                String chunkFilePath = chunkDirPath + File.separator + i;
                File chunkFile = new File(chunkFilePath);
                
                try {
                    fis = new FileInputStream(chunkFile);
                    int len;
                    while ((len = fis.read(buffer)) != -1) {
                        fos.write(buffer, 0, len);
                    }
                } finally {
                    if (fis != null) {
                        try {
                            fis.close();
                            fis = null;
                        } catch (IOException e) {
                            log.error("关闭分片文件输入流失败", e);
                        }
                    }
                }
            }
            
            // 确保所有数据都写入磁盘
            fos.flush();
            fos.close();
            fos = null;

            // 上传到MinIO
            fis = new FileInputStream(tempFile);
            url = minioUtil.uploadFile(fis, fileName, tempFile.length());
            log.info("文件上传成功，URL: {}", url);

            // 关闭输入流
            fis.close();
            fis = null;

            // 删除临时文件
            try {
                Files.deleteIfExists(Paths.get(chunkDirPath));
                Files.deleteIfExists(Paths.get(tempFilePath));
            } catch (IOException e) {
                log.warn("删除临时文件失败，但不影响上传结果: {}", e.getMessage());
            }

            return ResponseData.success(url);
        } catch (Exception e) {
            log.error("合并分片文件失败", e);
            throw new BizException(ErrorCodeEnum.FILE_UPLOAD_FAILED);
        } finally {
            // 关闭文件流
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    log.error("关闭合并文件输出流失败", e);
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    log.error("关闭合并文件输入流失败", e);
                }
            }
        }
    }
}
